package com.zhz.redis.util;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.params.SetParams;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @program: idempotent_redis
 * @description: 单节点redis分布式锁
 * @author: zhanghz001
 * @create: 2021-03-16 10:02
 **/
public class SingleRedisLock {
    private JedisPool jedisPool = new JedisPool("192.168.23.129", 6379);
    private long lockLeaseTime = 30000;
    private long timeOut = 30000;
    
    /**
     * 加锁
     *
     * @param lockKey   redis的key
     * @param requestId redis的value
     * @return 返回加锁结果
     */
    public boolean tryLock(String lockKey, String requestId) {
        String threadName = Thread.currentThread().getName();
        Jedis jedis = this.jedisPool.getResource();
        
        //获取当前时间
        long start = System.currentTimeMillis();
        
        try {
            //cas获取锁
            for (; ; ) {
                String lockResult = jedis.set(lockKey, requestId,
                        SetParams.setParams().nx().px(lockLeaseTime));
                if ("OK".equals(lockResult)) {
                    System.out.println(threadName + "  获取锁成功");
                    return true;
                }
                //获取锁失败,需要看看是否超时
                System.out.println(threadName + "  获取锁失败,进入自旋");
                
                long l = System.currentTimeMillis() - start;
                if (l > timeOut) {
                    System.out.println(threadName + "   在规定的时间内没有获取到锁,退出自旋");
                    return false;
                }
                
                //等待一段时间再循环
                try {
                    TimeUnit.MILLISECONDS.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } finally {
            jedis.close();
        }
    }
    
    /**
     * 解锁
     *
     * @param lockKey   这个是锁的key
     * @param requestId 这个是value
     * @return 返回解锁情况
     */
    public boolean releaseLock(String lockKey, String requestId) {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + ":  释放锁");
        Jedis jedis = jedisPool.getResource();
        
        //通过lua脚本的使用,让查询和加锁编程原子性操作
        String lua =
                "if redis.call('get',KEYS[1]) == ARGV[1] then" +
                        "   return redis.call('del',KEYS[1]) " +
                        "else" +
                        "   return 0 " +
                        "end";
        try {
            Object result = jedis.eval(lua, Collections.singletonList(lockKey),
                    Collections.singletonList(requestId));
            if ("1".equals(result.toString())) {
                return true;
            }
            return false;
        } finally {
            jedis.close();
        }
    }
}
